/*
 * ==============================================================================
 *  Name        : WebClientEngine.cpp
 *  Part of     : WebClient
 *  Interface   : 
 *  Description : 
 *  Version     : 
 *
 *  Copyright (c) 2005-2006 Nokia Corporation.
 *  This material, including documentation and any related 
 *  computer programs, is protected by copyright controlled by 
 *  Nokia Corporation.
 * ==============================================================================
 */

// INCLUDE FILES
#include <avkon.hrh>
#include <cdbcols.h>
#include <aknnotewrappers.h>
#include <stringloader.h>
#include <http.h>
#include <EIKAPP.H>
#include <EIKENV.H>
#include <COMMDB.H> //link commdb.lib
#include <BAUTILS.H>

#include <http\rhttpresponse.h>
#include <http\thttphdrval.h>
#include <http\rhttpconnectioninfo.h>

#include "WebClientEngine.h"
#include "WebClient.pan"
#include "es_enum.h" //link esocksvr.lib 
#include <e32cmn.h>

// ----------------------------------------------------------------------------
// CWebClientEngine::NewL()
// Creates instance of CWebClientEngine.
// ----------------------------------------------------------------------------
//
CWebClientEngine* CWebClientEngine::NewL (MWebClientObserver* aObserver )
{
	CWebClientEngine* self = CWebClientEngine::NewLC (aObserver );
	CleanupStack::Pop (self );
	if (aObserver )
		aObserver->WebClientEvent (KHttpInited, 0, KErrNone );
	return self;
}

// ----------------------------------------------------------------------------
// CWebClientEngine::NewLC()
// Creates instance of CWebClientEngine.
// ----------------------------------------------------------------------------
//
CWebClientEngine* CWebClientEngine::NewLC (MWebClientObserver* aObserver )
{
	CWebClientEngine* self = new (ELeave) CWebClientEngine (aObserver );
	CleanupStack::PushL (self );
	self->ConstructL ();
	return self;
}

// ----------------------------------------------------------------------------
// CWebClientEngine::CWebClientEngine()
// First phase constructor.
// ----------------------------------------------------------------------------
//
CWebClientEngine::CWebClientEngine (MWebClientObserver* aObserver ) :
	iObserver (aObserver ), iRunning (EFalse ), i_pReceiveBuf (NULL),
	iNet (EFalse )
{
	// no implementation required
}

// ----------------------------------------------------------------------------
// CWebClientEngine::~CWebClientEngine()
// Destructor.
// ----------------------------------------------------------------------------
//
CWebClientEngine::~CWebClientEngine ()
{
	if (iRunning )
		CancelTransactionL ();
	iSession.Close ();
	iConnection.Close ();
	iSocketServ.Close ();
	if (i_pReceiveBuf != NULL )
		delete i_pReceiveBuf;
	if (iPostData != NULL )
		delete iPostData;
}

// ----------------------------------------------------------------------------
// CWebClientEngine::ConstructL()
// Second phase construction.
// ----------------------------------------------------------------------------
//
void CWebClientEngine::ConstructL ()
{
#ifdef _NOT_USER_SELECT_IAP_
	CCommsDatabase* db = CCommsDatabase::NewL (EDatabaseTypeIAP );
	CleanupStack::PushL (db );
	CCommsDbTableView* view = db->OpenTableLC (TPtrC (OUTGOING_WCDMA) );
	TInt dbErr = view->GotoFirstRecord ();
	TBuf<32> name;
	TBuf<32> apn;
	TUint32 iapID = 0;

	while (dbErr == KErrNone )
	{
		view->ReadUintL (TPtrC (COMMDB_ID), iapID ); //�����ID
		view->ReadTextL (TPtrC (COMMDB_NAME), name );//l�����
		view->ReadTextL (TPtrC (GPRS_APN), apn ); //��������,����ͨ������ֶ��жϽ������CMWAP����CMNET
		if (KErrNotFound != apn.FindF (_L("cmwap")) )
		{
#ifdef _DEBUG
			RDebug::Printf(">>>use wap gateway IAP : %d", iapID);
#endif
#ifdef _ReplaceWapGateway_
			iUseApnCMWAP = ETrue;
#endif
			break;
		}
		iapID = 0;
		dbErr = view->GotoNextRecord ();
		
	}

	CleanupStack::PopAndDestroy (); // view
	CleanupStack::PopAndDestroy (); // db
#endif
	//�����û�ѡ����������
	User::LeaveIfError (iSocketServ.Connect () );//RSocketServ
	User::LeaveIfError (iConnection.Open (iSocketServ ) );//RConnection
	TCommDbConnPref pref;
#ifdef _NOT_USER_SELECT_IAP_
	pref.SetIapId (iapID );

	pref.SetDialogPreference (ECommDbDialogPrefDoNotPrompt );
	pref.SetDirection (ECommDbConnectionDirectionOutgoing );
#endif
	
	iSession.OpenL ();//RHTTPSession
	iConnection.Start (pref );

	RStringPool pool = iSession.StringPool ();
	//移除302 跳转过滤
	iSession.FilterCollection().RemoveFilter( pool.StringF( HTTP::ERedirect, RHTTPSession::GetTable()));
		
	RHTTPConnectionInfo connInfo = iSession.ConnectionInfo ();
	// Attach to socket server
	connInfo.SetPropertyL (pool.StringF (HTTP::EHttpSocketServ, RHTTPSession::GetTable () ), THTTPHdrVal (iSocketServ.Handle () ) );
	// Attach to connection
	TInt connPtr = REINTERPRET_CAST(TInt, &iConnection);
	connInfo.SetPropertyL (pool.StringF (HTTP::EHttpSocketConnection,RHTTPSession::GetTable () ), THTTPHdrVal (connPtr ) );
	TUint count;
	TConnectionInfo info;
	TPckg<TConnectionInfo> pck (info );
	TInt code;
	code = iConnection.EnumerateConnections (count );
	code = iConnection.GetConnectionInfo (1, pck );
	
}

// ----------------------------------------------------------------------------
// CWebClientEngine::SetHeaderL()
// Used to set header value to HTTP request
// ----------------------------------------------------------------------------
//
void CWebClientEngine::SetHeaderL (RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue )
{
	RStringF valStr = iSession.StringPool ().OpenFStringL (aHdrValue );
	CleanupClosePushL (valStr );
	THTTPHdrVal val (valStr );
	aHeaders.SetFieldL (iSession.StringPool ().StringF (aHdrField, RHTTPSession::GetTable () ), val );
	CleanupStack::PopAndDestroy (&valStr );
}

void CWebClientEngine::AddHeaderL (RHTTPHeaders aHeaders, const TDesC8& aHeaderField, const TDesC8& aHeaderValue )
{
	RStringPool stringPool = iSession.StringPool ();
	RStringF fieldStr = stringPool.OpenFStringL (aHeaderField );
	RStringF valStr = stringPool.OpenFStringL (aHeaderValue );
	THTTPHdrVal headerVal (valStr );
	aHeaders.SetFieldL (fieldStr, headerVal );
	valStr.Close ();
	fieldStr.Close ();
}

//----------------------------------------------------------------------
// ��ȡ���䳤��
//----------------------------------------------------------------------
void CWebClientEngine::DumpRespContentLength (RHTTPTransaction & aTransaction )
{
	RStringF strContentLength = iSession.StringPool ().StringF (
			HTTP::EContentLength, RHTTPSession::GetTable () );
	
	RHTTPResponse resp = aTransaction.Response ();
	RHTTPHeaders hdr = resp.GetHeaderCollection ();
	THTTPHdrVal lengthVal;
	TInt rtn = hdr.GetField (strContentLength, 0, lengthVal );
	
	if (rtn == KErrNone )
	{
		if (iObserver )
			iObserver->WebClientEvent (KHttpHeaderContentLength,
					iQuerySessionId, lengthVal.Int () );
	}
	
}

// ----------------------------------------------------------------------------
// CWebClientEngine::DumpRespHeadersL(RHTTPTransaction& aTransaction)
// Used to display HTTP header field names and values
// ----------------------------------------------------------------------------
//
void CWebClientEngine::DumpRespHeadersL (RHTTPTransaction& aTransaction )
{
	RHTTPResponse resp = aTransaction.Response ();
	RStringPool strP = aTransaction.Session ().StringPool ();
	RHTTPHeaders hdr = resp.GetHeaderCollection ();
	THTTPHdrFieldIter it = hdr.Fields ();
	
	//HBufC* headerField = HBufC::NewLC (KMaxHeaderNameLength + KMaxHeaderValueLength );
	//HBufC* fieldValBuf = HBufC::NewLC (KMaxHeaderValueLength );

	while (!it.AtEnd () )
	{
		HBufC8 *headerField = NULL;
		HBufC8 *fieldValBuf = NULL;
		RStringTokenF fieldName = it ();
		RStringF fieldNameStr = strP.StringF (fieldName );
		THTTPHdrVal fieldVal;
		TInt rtn = hdr.GetField (fieldNameStr, 0, fieldVal );
		//TPtrC8 ptrC;
		//TInt rtn = hdr.GetRawField (fieldNameStr, ptrC );
		
		if (rtn != KErrNotFound )
		{
			const TDesC8 &fieldNameDesC = fieldNameStr.DesC ();
			headerField = fieldNameDesC.AllocL ();
			//fieldValBuf = ptrC.AllocL ();
			
			 switch (fieldVal.Type () )
			{
			// the value is an integer
			case THTTPHdrVal::KTIntVal:
				fieldValBuf = HBufC8::NewL (16 );
				fieldValBuf->Des ().Num (fieldVal.Int () );
				break;
				//// the value is a not case-sensitive string
			case THTTPHdrVal::KStrFVal:
			{
				RStringF fieldValStrF = strP.StringF (fieldVal.StrF () );
				const TDesC8& fieldValDesC = fieldValStrF.DesC ();
				fieldValBuf = fieldValDesC.AllocL ();
			}
				break;
				// the value is a case-sensitive string
			case THTTPHdrVal::KStrVal:
			{
				RString fieldValStr = strP.String (fieldVal.Str () );
				const TDesC8& fieldValDesC = fieldValStr.DesC ();
				fieldValBuf = fieldValDesC.AllocL ();
			}
				break;
				// the value is a date/time
			case THTTPHdrVal::KDateVal:
			{
				TDateTime date = fieldVal.DateTime ();
				TBuf<KMaxDateTimeStringLength> dateTimeString;
				TTime t (date );
				t.FormatL (dateTimeString, KDateFormat );
				fieldValBuf = HBufC8::NewL (KMaxDateTimeStringLength );
				fieldValBuf->Des ().Copy (dateTimeString );
			}
				break;
				// the value is type is unknown
			default:
				break;
			}
			 

			// Display HTTP header field name and value
			//headerField->Des ().Append (KColon );
			//headerField->Des ().Append (*fieldValBuf );
			if (iObserver )
				iObserver->WebClientHeaderReceived (*headerField, *fieldValBuf,
						iQuerySessionId );
			/*
			 // Display realm for WWW-Authenticate header
			 RStringF wwwAuth = strP.StringF (HTTP::EWWWAuthenticate, RHTTPSession::GetTable () );
			 if (fieldNameStr == wwwAuth )
			 {
				 // check the auth scheme is 'basic'
				 RStringF basic = strP.StringF (HTTP::EBasic, RHTTPSession::GetTable () );
				 RStringF realm = strP.StringF (HTTP::ERealm, RHTTPSession::GetTable () );
				 THTTPHdrVal realmVal;
				 if ((fieldVal.StrF () == basic) && (!hdr.GetParam (wwwAuth, realm, realmVal )) )
				 {
					 RStringF realmValStr = strP.StringF (realmVal.StrF () );
					 fieldValBuf = realmValStr.DesC().AllocL();
					 headerField = Krealm().AllocL();
					 if (iObserver )
						 iObserver->WebClientHeaderReceived (*headerField, *fieldValBuf, iQuerySessionId);
				 }
			 }
			 */

		}

		delete fieldValBuf;
		fieldValBuf = NULL;
		delete headerField;
		headerField = NULL;
		
		++it;
		
	}
	//CleanupStack::PopAndDestroy (2);//fieldValBuf, headerField
}

// ----------------------------------------------------------------------------
// CWebClientEngine::HandleRunErrorL()
// Called from MHFRunError() when *leave* occurs in handling of transaction event.
// ----------------------------------------------------------------------------
//
void CWebClientEngine::HandleRunErrorL (TInt aError )
{
	if (iObserver )
		iObserver->WebClientEvent (KHttpMHFRunError, iQuerySessionId, aError );
}

// ----------------------------------------------------------------------------
// CWebClientEngine::IssueHTTPGetL()
// Start a new HTTP GET transaction.
// ----------------------------------------------------------------------------
//
void CWebClientEngine::IssueHTTPGetL (const TDesC8& aUri, TInt aSessionId, TBool aReplaceHost, TBool aBufferAll )
{
	//iUseApnCMWAP = ETrue;
	iQuerySessionId = aSessionId;
	i_isBufferAll = aBufferAll;

	TBuf8<512> newUri; //url �256           
	TBuf8<40> targetIp;
	if (iUseApnCMWAP )
	{
		ReplaceUriL (aUri, KWapGetwayIp, newUri, targetIp );
	}
	else
	{
		newUri.Copy (aUri );
	}

	// Parse string to URI (as defined in RFC2396)
	TUriParser8 uri;
	uri.Parse (newUri );

#ifdef _DEBUG
	RDebug::Printf(">>>Http get url:%s", (const char*)(newUri.Ptr()));
#endif
	
	// Get request method string for HTTP GET
	RStringF method = iSession.StringPool ().StringF (HTTP::EGET, RHTTPSession::GetTable () );
	
	// Open transaction with previous method and parsed uri. This class will
	// receive transaction events in MHFRunL and MHFRunError.
	iTransaction = iSession.OpenTransactionL (uri, *this, method );
	// Set headers for request; user agent and accepted content type
	RHTTPHeaders hdr = iTransaction.Request ().GetHeaderCollection ();
	
	if (iUseApnCMWAP )
	{
		//���?X-Online-Host
		AddHeaderL (hdr, _L8("X-Online-Host"), targetIp );
	}
/*
	SetHeaderL (hdr, HTTP::EUserAgent, _L8("UCWEB/6.00"));
	SetHeaderL (hdr, HTTP::EAccept, KAccept );
	//SetHeaderL (hdr, HTTP::EContentType, _L8("multipart/form-data"));
	SetHeaderL (hdr, HTTP::EAcceptLanguage, KAcceptLanguage );
	SetHeaderL (hdr, HTTP::EAcceptCharset, KAcceptCharset );
	SetHeaderL (hdr, HTTP::EReferer, aUri );
	SetHeaderL (hdr, HTTP::EAcceptEncoding, _L8("gzip, deflate"));
	SetHeaderL (hdr, HTTP::EConnection, KKeepAlive );
	AddHeaderL (hdr, _L8("Proxy-Connection"), _L8("keep-alive"));
	//SetHeaderL(hdr, HTTP::ECookie, _L8("Cookie"));
	//AddHeaderL(hdr, _L8("X-Up-Calling-Line-ID"), _L8("13612444588"));
*/
	 SetHeaderL( hdr, HTTP::EUserAgent, KUserAgent );
	 SetHeaderL( hdr, HTTP::EAccept, KAccept );
	 SetHeaderL( hdr, HTTP::EAcceptCharset, KAcceptCharset);
	 SetHeaderL( hdr, HTTP::EAcceptLanguage, KAcceptLanguage);
	 //SetHeaderL( hdr, HTTP::EIfModifiedSince, KDateFormat);


	//��ս��ջ�����
	if (i_pReceiveBuf )
	{
		i_pReceiveBuf->Des ().Zero ();
	}

	// Submit the transaction. After this the framework will give transaction
	// events via MHFRunL and MHFRunError.
	iTransaction.SubmitL ();

	iRunning = ETrue;
	if (iObserver )
		iObserver->WebClientEvent (KHttpConnecting, iQuerySessionId, 0 );
}

// ----------------------------------------------------------------------------
// CWebClientEngine::IssueHTTPPostL()
//
// Start a new HTTP POST transaction.
// ----------------------------------------------------------------------------
void CWebClientEngine::IssueHTTPPostL (const TDesC8& aUri, const TDesC8& aBody, TInt aSessionId, TBool aBufferAll )
{
	iQuerySessionId = aSessionId;
	i_isBufferAll = aBufferAll;

	TBuf8<512> newUri; //url �256           
	TBuf8<40> targetIp;
	if (iUseApnCMWAP )
	{
		ReplaceUriL (aUri, KWapGetwayIp, newUri, targetIp );
	}
	else
	{
		newUri.Copy (aUri );
	}

	// Parse string to URI
	TUriParser8 uri;
	uri.Parse (newUri );

#ifdef _DEBUG
	RDebug::Printf(">>>Http Post url: %s",(const char*)(newUri.Ptr()));
	//RLog::Log(_L8("Http Post"), aUri);
	//RLog::Log(_L8("New url"), newUri);
#endif
	// Copy data to be posted into member variable; iPostData is used later in
	// methods inherited from MHTTPDataSupplier.
	delete iPostData;
	iPostData = aBody.AllocL ();

	// Get request method string for HTTP POST
	RStringF method = iSession.StringPool ().StringF (HTTP::EPOST,
			RHTTPSession::GetTable () );
	
	// Open transaction with previous method and parsed uri. This class will 
	// receive transaction events in MHFRunL and MHFRunError.
	iTransaction = iSession.OpenTransactionL (uri, *this, method );

	// Set headers for request; user agent, accepted content type and body's 
	// content type.
	RHTTPHeaders hdr = iTransaction.Request ().GetHeaderCollection ();
	
	if (iUseApnCMWAP )
	{
		//���?X-Online-Host
		AddHeaderL (hdr, _L8("X-Online-Host"), targetIp );
	}
	//SetHeaderL(hdr, HTTP::EAccept, KAccept);
	//SetHeaderL (hdr, HTTP::EContentType, _L8("application/x-www-form-urlencoded"));
	SetHeaderL (hdr, HTTP::EContentType, _L8("multipart/form-data"));
	SetHeaderL (hdr, HTTP::EUserAgent, _L8("MobileExplorer/3.00"));
	SetHeaderL (hdr, HTTP::EAcceptCharset, KAcceptCharset );
	SetHeaderL (hdr, HTTP::EAcceptLanguage, KAcceptLanguage );
	SetHeaderL (hdr, HTTP::EConnection, KKeepAlive );
	SetHeaderL (hdr, HTTP::EReferer, aUri );
	//SetHeaderL(hdr, HTTP::EAcceptEncoding, KAcceptEncoding);
	AddHeaderL (hdr, _L8("Proxy-Connection"), _L8("keep-alive"));

	// Set this class as an data supplier. Inherited MHTTPDataSupplier methods
			// are called when framework needs to send body data.
			MHTTPDataSupplier* dataSupplier = this;
			iTransaction.Request().SetBody(*dataSupplier);

			//��ս��ջ�����
			if(i_pReceiveBuf)
			{
				i_pReceiveBuf->Des().Zero();
			}

			// Submit the transaction. After this the framework will give transaction
			// events via MHFRunL and MHFRunError.
			iTransaction.SubmitL();

			iRunning = ETrue;
			if(iObserver)
			iObserver->WebClientEvent(KHttpConnecting, iQuerySessionId, KErrNone);
		}

	// ----------------------------------------------------------------------------
	// CWebClientEngine::IssueHTTPPostL()
	//
	// Start a new HTTP POST transaction.
	// ----------------------------------------------------------------------------

void CWebClientEngine::IssueHTTPPostL (const TDesC8& aUri, const TDesC8& aBody, const TDesC8& aCookie, TInt aSessionId, TBool aBufferAll )
{
	
	iQuerySessionId = aSessionId;
	i_isBufferAll = aBufferAll;

	TBuf8<512> newUri; //url �256           
	TBuf8<40> targetIp;
	if (iUseApnCMWAP )
	{
		ReplaceUriL (aUri, KWapGetwayIp, newUri, targetIp );
	}
	else
	{
		newUri.Copy (aUri );
	}
#ifdef _DEBUG
	RDebug::Printf(">>>Http Post(cookie) url: %s",(const char*)(newUri.Ptr()));
#endif
	
	// Parse string to URI
	TUriParser8 uri;
	uri.Parse (newUri );

	// Copy data to be posted into member variable; iPostData is used later in
	// methods inherited from MHTTPDataSupplier.
	delete iPostData;
	iPostData = aBody.AllocL ();

	// Get request method string for HTTP POST
	RStringF method = iSession.StringPool ().StringF (HTTP::EPOST,
			RHTTPSession::GetTable () );
	
	// Open transaction with previous method and parsed uri. This class will 
	// receive transaction events in MHFRunL and MHFRunError.
	iTransaction = iSession.OpenTransactionL (uri, *this, method );

	//ptrUri = POST http://218.200.244.92/PullServlet;xid=H8P8Ch7y!71430103!-596044095?SOD=true&MISC_U=....

	// Set headers for request; user agent, accepted content type and body's 
	// content type.
	RHTTPHeaders hdr = iTransaction.Request ().GetHeaderCollection ();
	if (iUseApnCMWAP )
	{
		//���?X-Online-Host
		AddHeaderL (hdr, _L8("X-Online-Host"), targetIp );
	}
	SetHeaderL (hdr, HTTP::EContentType, _L8("application/x-www-form-urlencoded"));
	SetHeaderL (hdr, HTTP::EUserAgent, _L8("MobileExplorer/3.00"));
	SetHeaderL (hdr, HTTP::EAccept, KAccept );
	SetHeaderL (hdr, HTTP::EAcceptCharset, KAcceptCharset );
	SetHeaderL (hdr, HTTP::EAcceptLanguage, KAcceptLanguage );
	SetHeaderL (hdr, HTTP::EConnection, KKeepAlive );
	SetHeaderL (hdr, HTTP::EReferer, aUri );
	SetHeaderL (hdr, HTTP::ECookie, aCookie );// _L8("xid=H8P8Ch7y!71430103!-596044095"));
	SetHeaderL (hdr, HTTP::ECookie2, _L8("$Version=1"));

	// Set this class as an data supplier. Inherited MHTTPDataSupplier methods
	// are called when framework needs to send body data.
	MHTTPDataSupplier* dataSupplier = this;
	iTransaction.Request ().SetBody (*dataSupplier );

	//��ս��ջ�����
	if (i_pReceiveBuf )
	{
		i_pReceiveBuf->Des ().Zero ();
	}
	// Submit the transaction. After this the framework will give transaction
	iTransaction.SubmitL ();
	iRunning = ETrue;
	
	if (iObserver )
		iObserver->WebClientEvent (KHttpConnecting, iQuerySessionId, KErrNone );
}

// ----------------------------------------------------------------------------
// CWebClientEngine::CancelTransactionL()
// Cancels currently running transaction and frees resources related to it.
// ----------------------------------------------------------------------------
//
void CWebClientEngine::CancelTransactionL ()
{
	if (!iRunning )
		return;

	// Close() also cancels transaction (Cancel() can also be used but 
	// resources allocated by transaction must be still freed with Close())
	iTransaction.Close ();
	// Not running anymore
	iRunning = EFalse;
	if (iObserver )
		iObserver->WebClientEvent (KHttpTransactionCancel, iQuerySessionId, 0 );
}

// ----------------------------------------------------------------------------
// CWebClientEngine::SetCallBack()
// Set pointer to CApplicationUi instance
// ----------------------------------------------------------------------------
//
//void CWebClientEngine::SetCallBack( CWebClientAppUi* aCallBack )
//    {
//    iApplicationUi = aCallBack;
//    }

// ----------------------------------------------------------------------------
// CWebClientEngine::MHFRunL()
// Inherited from MHTTPTransactionCallback
// Called by framework to pass transaction events.
// ----------------------------------------------------------------------------
//
void CWebClientEngine::MHFRunL (RHTTPTransaction aTransaction, const THTTPEvent& aEvent )
{
	switch (aEvent.iStatus )
	{
	case THTTPEvent::EGotResponseHeaders:
	{
		// HTTP response headers have been received. Use
		// aTransaction.Response() to get the response. However, it's not
		// necessary to do anything with the response when this event occurs.

		// Get HTTP status code from header (e.g. 200)
		RHTTPResponse resp = aTransaction.Response ();
		TInt status = resp.StatusCode ();
		if (iObserver )
			iObserver->WebClientEvent (KHttpResponseCode, iQuerySessionId,
					status );
		// Display header field names and value
		DumpRespHeadersL (aTransaction );
		//iObserver->WebClientEvent(KHttpHeaderReceived, status);
		if (status == 200 )
		{
			DumpRespContentLength (aTransaction );
		}
	}
		break;
		
	case THTTPEvent::EGotResponseBodyData:
	{
		
		// Part (or all) of response's body data received. Use 
		// Get the body data supplier
		MHTTPDataSupplier* body = aTransaction.Response ().Body ();
		TPtrC8 dataChunk;
		
		// GetNextDataPart() returns ETrue, if the received part is the last 
		TBool isLast = body->GetNextDataPart (dataChunk );
		//接收数据长度
		if (iObserver )
			iObserver->WebClientEvent (KHttpBodyPartReceived, iQuerySessionId,
					dataChunk.Length () );

		if (i_isBufferAll )
		{
			//缓存接收数据
			if (!i_pReceiveBuf )
			{
				i_pReceiveBuf = HBufC8::NewL (KReceiverBufSize);
			}
			TPtr8 ptr8 (i_pReceiveBuf->Des () );
			TInt freeSize = ptr8.MaxLength () - ptr8.Length ();
			if (freeSize < dataChunk.Size () )
			{
				TInt newSize = ptr8.MaxLength ()
						+ (((freeSize + KReceiverBufSize)
								>= dataChunk.Length ()) ? KReceiverBufSize
								: dataChunk.Length ());
				i_pReceiveBuf = i_pReceiveBuf->ReAllocL (newSize );
				ptr8.Set (i_pReceiveBuf->Des () );
			}
			ptr8.Append (dataChunk );
		}
		else
		{
			if (iObserver )
				iObserver->ClientBodyReceived (dataChunk, isLast );
		}
		
		// Always remember to release the body data.
		body->ReleaseData ();
	}
		break;
		
	case THTTPEvent::EResponseComplete:
	{
		// Indicates that header & body of response is completely received.
		if (iObserver )
		{
			if (i_pReceiveBuf )
				iObserver->WebClientBodyReceivedComplete (*i_pReceiveBuf,
						iQuerySessionId );
			else
				iObserver->WebClientBodyReceivedComplete (KNullDesC8,
						iQuerySessionId );
			iObserver->WebClientEvent (KHttpTransactionComplete,
					iQuerySessionId );
		}
	}
		break;
	case THTTPEvent::ESucceeded:
	{
		// Indicates that transaction succeeded. 
		if (iObserver )
			iObserver->WebClientEvent (KHttpTransactionSucceed, iQuerySessionId );

		// Transaction can be closed now. It's not needed anymore.
		aTransaction.Close ();
		iRunning = EFalse;
	}
		break;
	case THTTPEvent::EFailed:
	{
		// Transaction completed with failure. 
		if (iObserver )
			iObserver->WebClientEvent (KHttpTransactionFailed, iQuerySessionId );
		aTransaction.Close ();
		iRunning = EFalse;
	}
		break;
	case THTTPEvent::ERedirectedTemporarily:
	{
		DumpRespHeadersL (aTransaction );
		
	}
		break;
	default:
		// There are more events in THTTPEvent, but they are not usually 
		// needed. However, event status smaller than zero should be handled 
		// correctly since it's error.
	{
		if (aEvent.iStatus < 0 )
		{
			if (iObserver )
				iObserver->WebClientEvent (KHttpTransactionError,
						iQuerySessionId, aEvent.iStatus );

			// Just close the transaction on errors
			aTransaction.Close ();
			iRunning = EFalse;
		}
		else
		{
			// Other events are not errors (e.g. permanent and temporary redirections)
			if (iObserver )
				iObserver->WebClientEvent (KHttpUnrecognisedEvent,
						iQuerySessionId, aEvent.iStatus );
		}
	}
		break;
	}
}

// ----------------------------------------------------------------------------
// CWebClientEngine::MHFRunError()
// Inherited from MHTTPTransactionCallback
// Called by framework when *leave* occurs in handling of transaction event.
// These errors must be handled, or otherwise HTTP-CORE 6 panic is thrown.
// ----------------------------------------------------------------------------
//
TInt CWebClientEngine::MHFRunError (TInt aError, RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/)
{
	// Handle error and return KErrNone.
	TRAPD( err, HandleRunErrorL( aError ) );
	if (err )
		Panic (EClientEngine );
	return KErrNone;
}

// ----------------------------------------------------------------------------
// CWebClientEngine::GetCredentialsL()
//
// Inherited from MHTTPAuthenticationCallback
// Called by framework when we requested authenticated page and framework 
// needs to know username and password.
// ----------------------------------------------------------------------------
TBool CWebClientEngine::GetCredentialsL (const TUriC8& /*aUri*/, RString /*aRealm*/, RStringF /*aAuthenticationType*/, RString& /*aUsername*/, RString& /*aPassword*/)
{
	//// aURI, aReal and aAuthenticationType are informational only. We only need 
	//// to set aUsername and aPassword and return ETrue, if aUsername and 
	//// aPassword are provided by user.

	//// Query user name and password
	//TBuf<KMaxUserNameLength> userName;
	//TBuf<KMaxPasswordLength> password;
	//CAknMultiLineDataQueryDialog* dlg = 
	//    CAknMultiLineDataQueryDialog::NewL( userName, password );

	//if ( !dlg->ExecuteLD( R_WEBCLIENT_DIALOG_USER_PASSWORD_QUERY ))
	//    return EFalse; // No credentials given; must return EFalse

	//// Set aUsername and aPassword
	//TBuf8<KMaxUserNameLength> temp;
	//temp.Copy( userName );
	//TRAPD( err, aUsername = aRealm.Pool().OpenStringL( temp ));
	//if ( !err ) 
	//    {
	//    temp.Copy( password );
	//    TRAP( err, aPassword = aRealm.Pool().OpenStringL( temp ));
	//    if ( !err ) return ETrue;
	//    }

	//// Return ETrue if user has given credentials (username and password), 
	//// otherwise EFlase
	return EFalse;
}

//��ȡiap���������
void CWebClientEngine::ReadIapIDL (RFileReadStream& aStream, TUint32& aIapID )
{
	aIapID = aStream.ReadUint32L ();
}

//д����
void CWebClientEngine::WriteIapIDL (RFileWriteStream& aStream, TUint32& aIapID )
{
	aStream.WriteUint32L (aIapID );
}

// ----------------------------------------------------------------------------
// CWebClientEngine::GetNextDataPart()
//
// Inherited from MHTTPDataSupplier
// Called by framework when next part of the body is needed. In this example 
// this provides data for HTTP post.
// ----------------------------------------------------------------------------
TBool CWebClientEngine::GetNextDataPart (TPtrC8& aDataPart )
{
	//	TBool retVal = EFalse;
	aDataPart.Set (iPostData->Des () );
	//	retVal = (aDataPart.Length() == 0);
	//	iDataAvailable=retVal;
	return ETrue;
}

// ----------------------------------------------------------------------------
// CWebClientEngine::ReleaseData()
//
// Inherited from MHTTPDataSupplier
// Called by framework. Allows us to release resources needed for previous
// chunk. (e.g. free buffers)
// ----------------------------------------------------------------------------
void CWebClientEngine::ReleaseData ()
{
	// It's safe to delete iPostData now.
	/*delete iPostData;
	 iPostData = NULL;*/

	// When sending data in multiple parts we must notify the framework here:
	// (the framework can call GetNextDataPart() when we notify it by calling
	//  NotifyNewRequestBodyPartL())

	/*if(iDataAvailable)
	 iTransaction.NotifyNewRequestBodyPartL();*/
	/*if (err != KErrNone)
	 Panic(EClientEngine);*/
}

// ----------------------------------------------------------------------------
// CWebClientEngine::Reset()
//
// Inherited from MHTTPDataSupplier
// Called by framework to reset the data supplier. Indicates to the data 
// supplier that it should return to the first part of the data.	
// In practise an error has occured while sending data, and framework needs to 
// resend data.
// ----------------------------------------------------------------------------
TInt CWebClientEngine::Reset ()
{
	// Nothing needed since iPostData still exists and contains all the data. 
	// (If a file is used and read in small parts we should seek to beginning 
	// of file and provide the first chunk again in GetNextDataPart() )
	return KErrNone;
}

// ----------------------------------------------------------------------------
// CWebClientEngine::OverallDataSize()
//
// Inherited from MHTTPDataSupplier
// Called by framework. We should return the expected size of data to be sent.
// If it's not know we can return KErrNotFound (it's allowed and does not cause
// problems, since HTTP protocol allows multipart bodys without exact content 
// length in header).
// ----------------------------------------------------------------------------
TInt CWebClientEngine::OverallDataSize ()
{
	if (iPostData )
		return iPostData->Length ();
	else
		return KErrNotFound;
}

/**
 * �滻url, ����post�����Ĵ�������
 */
void CWebClientEngine::ReplaceUriL (const TDesC8& aRowUri, const TDesC8& aNewIP, TDes8& aNewUri, TDes8& aRowIP )
{
	_LIT8(KScheme, "://");
	TInt i = aRowUri.Find (KScheme () );
	User::LeaveIfError (i );
	i += 3;
	aNewUri = aRowUri.Left (i );
	aNewUri.Append (aNewIP );

	TPtrC8 p = aRowUri.Right (aRowUri.Length () - i );
	_LIT8(KSeparator, "/");
	i = p.Find (KSeparator () );
	User::LeaveIfError (i );
	aRowIP = p.Left (i );
	
	aNewUri.Append (p.Right (p.Length () - i ) );
}

void CWebClientEngine::ReadDataL ()
{
	/*���ļ���ȡ*/
	RFs fs;
	User::LeaveIfError (fs.Connect () );
	RFileReadStream in;
	in.PushL (); // in on cleanup stack
	//User::LeaveIfError(in.Open(fs, AddPath(KSettingsStore), EFileRead));
	TFileName fullPath;
#ifdef __WINSCW__
	fullPath.Copy(_L("c:"));
#else
	TParse parse;
	parse.Set (
			CEikonEnv::Static ()->EikAppUi ()->Application ()->AppFullName (),
			NULL, NULL);
	fullPath.Copy (parse.Drive () );
#endif
	fullPath.Append (_L("ddd"));
	TInt err = KErrNone;
	if (in.Open (fs, fullPath, EFileRead ) == KErrNone )
	{
		TRAP(err, InternalizeL(in));
	}
	in.Close ();
	CleanupStack::PopAndDestroy (); // in
	fs.Close ();
}

void CWebClientEngine::InternalizeL (RReadStream& aStream )
{
	iRing = aStream.ReadInt8L ();
	iWall = aStream.ReadInt8L ();
	iMagazine = aStream.ReadInt8L ();
	iNet = aStream.ReadInt8L ();
}
